/*!  \file  SteDC.cpp
 *	  \brief  
 * 
 *   \details   details
 *   \author    Yordan Madzhunkov German Research School for Simulation Sciences GmbH
 *   \version   1.0
 *   \date      06/29/2013 11:20:23 PM
 *   \copyright GNU Public License.
 */
#include "SteDC.h"
#include "Matrix.h"
#include "setThreads.h"

extern "C" {
void dstedc_(
const char   * jobz, 	
const int    * n,
      double * d,
      double * e,
      double * z,
const int    * ldz,
      double * work,
const int    * lwork,
      int    * iwork,
const int    * liwork,
      int    * info);
}
SteDC::SteDC(): TriEigen("Lapack dstedc") {	
	setCompileTime(__DATE__, __TIME__); 
	canBeParallel = false;
}
bool SteDC::setNumberOfThreads(int nThreads_) {	
	assert(canBeParallel);
	SET_NUM_THREADS(nThreads_);
	nThreads = nThreads;
	return true;
}
void SteDC::compute(const Matrix & T, Matrix & Sigma, Matrix & Q ){
	reset();
	assert(T.isTriDiagonal() && Sigma.isDiagonal() && Q.isOrthogonal());
	char jobz = 'I';	int n = T.cols(), info = -1, ldq = Q.lda();
	double * e = NULL; allocate(e, n); 
	double * d    = Sigma.getModData();
	double * q    = Q.getModData(); Q.makeColMajor();
	memcpy(d, T.getData()    ,    n * sizeof(*d));
	memcpy(e, T.getOffDiagonal(), (n-1)* sizeof(*d));
	int lwork = -1, liwork = -1;
	double optW;
	int optIW;
	// calculates the optimal sizes of the WORK and IWORK arrays
	dstedc_(&jobz, &n, d, e, q,&ldq, &optW, &lwork, &optIW, &liwork, &info);
	success &= info == 0;
	if (info == 0) {
		lwork = (int) optW; 	liwork = (int) optIW;
		double *work = NULL; int *iwork = NULL;
		allocate(work, lwork); allocate(iwork, liwork);
		if (work && iwork ) {
			dstedc_(&jobz,&n, d, e, q, &ldq, work, &lwork, iwork, &liwork, &info);
			success &= info == 0;
		}
		delocate (iwork);	delocate ( work);
	}
	delocate(e);
};
BiNESteDC::BiNESteDC() : BiSVD( "NE dstedc" ) {
	aUpper     = true; 
	aLower     = false; 
	aUColMajor = true; 
	aVColMajor = true; 
	VColVec    = false;
	setTriEigen(*(new SteDC()));
	setCompileTime(__DATE__, __TIME__); 
};
BiNE2SteDC::BiNE2SteDC() : BiSVD( "NE2 dstedc" ) {
	aUpper     = true; 
	aLower     = false; 
	aUColMajor = true; 
	aVColMajor = true; 
	VColVec    = false;
	setTriEigen(*(new SteDC()));
	setCompileTime(__DATE__, __TIME__);
};
BiGKSteDC::BiGKSteDC() : BiSVD( "GK dstedc" ) {
	aUpper = true; 
	aLower = false; 
	aUColMajor = true; 
	aVColMajor = true; 
	VColVec = false;
	setTriEigen(*(new SteDC()));
	setCompileTime(__DATE__, __TIME__);
};
REGISTER(SteDC);
//REGISTER(BiNESteDC);
//REGISTER(BiNE2SteDC);
REGISTER(BiGKSteDC);
